

package com.szmmsoft.mp.common.fiter;

import cn.hutool.core.collection.CollectionUtil;

import com.szmmsoft.mp.common.config.XssConfig;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.http.server.PathContainer;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.util.pattern.PathPattern;
import org.springframework.web.util.pattern.PathPatternParser;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;

/**
 * XSS 过滤器
 *
 * @author whhya
 * @since 2.0.0
 */
@Component
@Slf4j
public class XssFilter extends OncePerRequestFilter implements Ordered {
    @Override
    public int getOrder() {
        return Ordered.LOWEST_PRECEDENCE - 20;
    }

    /**
     * 判断数组中是否存在匹配的路径
     *
     * @param requestUrl   请求地址
     * @param pathPatterns 指定匹配路径
     * @return true：匹配；false：不匹配
     */
    private static boolean isMatchPath(String requestUrl, List<String> pathPatterns) {
        for (String pattern : pathPatterns) {
            PathPattern pathPattern = PathPatternParser.defaultInstance.parse(pattern);
            PathContainer pathContainer = PathContainer.parsePath(requestUrl);
            if (pathPattern.matches(pathContainer)) {
                log.info("路由匹配进行拦截{}", requestUrl);
                return true;
            }
        }
        log.info("路由匹配进行拦截{}错误", requestUrl);
        return false;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest servletRequest, HttpServletResponse servletResponse, FilterChain filterChain) throws ServletException, IOException {
        log.info("XssFilter:{}", servletRequest.getServletPath());
        // 未开启 XSS 过滤，则直接跳过
        if (XssConfig.ENABLED) {
            // 放行路由：忽略 XSS 过滤
            List<String> excludePatterns = XssConfig.EXCLUDEPATTERNS;
            if (CollectionUtil.isNotEmpty(excludePatterns) && isMatchPath(servletRequest.getServletPath(), excludePatterns)) {
                filterChain.doFilter(servletRequest, servletResponse);
                return;
            }
            // 拦截路由：执行 XSS 过滤
            List<String> includePatterns = XssConfig.INCLUDEPATTERNS;
            if (CollectionUtil.isNotEmpty(includePatterns)) {
                if (isMatchPath(servletRequest.getServletPath(), includePatterns)) {
                    filterChain.doFilter(new XssServletRequestWrapper(servletRequest), servletResponse);
                } else {
                    filterChain.doFilter(servletRequest, servletResponse);
                }
                return;
            }
            // 默认：执行 XSS 过滤
            filterChain.doFilter(new XssServletRequestWrapper(servletRequest), servletResponse);
            return;
        }
        filterChain.doFilter(servletRequest, servletResponse);

    }
}
